/**
 * @file my_vector.h
 * @brief 向量
 * @details 向量相关运算
 * @author all
 * @date 2023/11/7
 * @version 1.0
 * @par Update Record:
 * - 2023/11/3 创建文档
 * - 2023/11/7 添加注释
*/
/********************<start>**********************/
#ifndef MY_VECTOR_H
#define MY_VECTOR_H

/********************<include>********************/
#include "my_scalar.h"

namespace my_tf{

/********************<class>**********************/
    /**
     * @brief 三维向量类
     */
    class Vector3
    {
    public:
        double m_floats[4];
        /**
         * @brief 默认构造函数
         */
        inline Vector3(){}
        /**
         * @brief 构造函数，根据给定的x、y、z分量创建向量
         * @param x x分量
         * @param y y分量
         * @param z z分量
         */
        inline Vector3(const double& x,const double& y,const double& z)
        {
            m_floats[0]=x;
            m_floats[1]=y;
            m_floats[2]=z;
            m_floats[3]=double(0.);
        }
        /**
         * @brief 向量加法赋值运算符
         * @param v 另一个向量
         * @return 相加后的向量
         */
	    inline Vector3& operator+=(const Vector3& v)
	    {

            m_floats[0] += v.m_floats[0]; m_floats[1] += v.m_floats[1];m_floats[2] += v.m_floats[2];
            return *this;
        }
        /**
         * @brief 向量减法赋值运算符
         * @param v 另一个向量
         * @return 相减后的向量
         */
        inline Vector3& operator-=(const Vector3& v) 
        {
            m_floats[0] -= v.m_floats[0]; m_floats[1] -= v.m_floats[1];m_floats[2] -= v.m_floats[2];
            return *this;
        }
        /**
         * @brief 向量乘以标量的赋值运算符
         * @param s 标量
         * @return 乘以标量后的向量
         */
        inline Vector3& operator*=(const double& s)
        {
            m_floats[0] *= s; m_floats[1] *= s;m_floats[2] *= s;
            return *this;
        }
        /**
         * @brief 向量除以标量的赋值运算符
         * @param s 标量
         * @return 除以标量后的向量
         */
        inline Vector3& operator/=(const double& s) 
        {
            myAssert(s != double(0.0));
            return *this *= double(1.0) / s;
        }
        /**
         * @brief 计算该向量与另一个向量的点积
         * @param v 另一个向量
         * @return 点积结果
         */
        inline double dot(const Vector3& v) const
        {
            return m_floats[0] * v.m_floats[0] + m_floats[1] * v.m_floats[1] +m_floats[2] * v.m_floats[2];
        }
        /**
         * @brief 计算向量的长度
         * @return 向量的长度
         */
        inline double length() const
        {
            return tfSqrt(length2());
        }
        /**
         * @brief 计算向量的平方长度
         * @return 向量的平方长度
         */
        inline double length2() const
        {
            return dot(*this);
        } 
        /**
         * @brief 计算该向量与另一个向量的距离
         * @param v 另一个向量
         * @return 距离结果
         */
        inline double distance(const Vector3& v) const;      
        /**
         * @brief 计算该向量与另一个向量的平方距离
         * @param v 另一个向量
         * @return 平方距离结果
         */
        inline double distance2(const Vector3& v) const;   
        /**
         * @brief 对向量进行归一化
         * @return 归一化后的向量
         */
        inline Vector3& normalize() 
        {
            return *this /= length();
        }
        /**
         * @brief 计算该向量与另一个向量的夹角
         * @param v 另一个向量
         * @return 夹角结果
         */
        inline double angle(const Vector3& v) const 
        {
            double s = tfSqrt(length2() * v.length2());
            myAssert(s != double(0.0));
            return tfAcos(dot(v) / s);
        }
        /**
         * @brief 计算该向量与另一个向量的叉积
         * @param v 另一个向量
         * @return 叉积结果
         */
        inline Vector3 cross(const Vector3& v) const
        {
            return Vector3(
                m_floats[1] * v.m_floats[2] -m_floats[2] * v.m_floats[1],
                m_floats[2] * v.m_floats[0] - m_floats[0] * v.m_floats[2],
                m_floats[0] * v.m_floats[1] - m_floats[1] * v.m_floats[0]);
        }
        /**
         * @brief 获取向量的x分量
         * @return x分量
         */
        inline const double& getX() const { return m_floats[0]; }
        /**
         * @brief 获取向量的y分量
         * @return y分量
         */
        inline const double& getY() const { return m_floats[1]; }
        /**
         * @brief 获取向量的z分量
         * @return z分量
         */
        inline const double& getZ() const { return m_floats[2]; }
        /**
         * @brief 设置向量的x分量
         * @param x x分量
         */
        inline void	setX(double x) { m_floats[0] = x;};
        /**
         * @brief 设置向量的y分量
         * @param y y分量
         */
        inline void	setY(double y) { m_floats[1] = y;};
        /**
         * @brief 设置向量的z分量
         * @param z z分量
         */
        inline void	setZ(double z) {m_floats[2] = z;};
        /**
         * @brief 设置向量的w分量
         * @param w w分量
         */
        inline void	setW(double w) { m_floats[3] = w;};
        /**
         * @brief 获取向量的x分量
         * @return x分量
         */
        inline const double& x() const { return m_floats[0]; }
        /**
         * @brief 获取向量的y分量
         * @return y分量
         */
        inline const double& y() const { return m_floats[1]; }
        /**
         * @brief 获取向量的z分量
         * @return z分量
         */
        inline const double& z() const { return m_floats[2]; }
        /**
         * @brief 获取向量的w分量
         * @return w分量
         */
        inline const double& w() const { return m_floats[3]; }
        /**
         * @brief 设置向量的值
         * @param x x分量
         * @param y y分量
         * @param z z分量
         */
        inline void 	setValue(const double& x, const double& y, const double& z)
		{
			m_floats[0]=x;
			m_floats[1]=y;
			m_floats[2]=z;
			m_floats[3] = double(0.);
		}
        /**
         * @brief 隐式转换为double类型的指针
         * @return double类型的指针
         */
        inline	operator       double *()       { return &m_floats[0]; }
        /**
         * @brief 隐式转换为const double类型的指针
         * @return const double类型的指针
         */
	    inline	operator const double *() const { return &m_floats[0]; }
    };
    /**
     * @brief 向量加法运算符
     * @param v1 向量1
     * @param v2 向量2
     * @return 相加后的向量
     */
    inline Vector3 
    operator+(const Vector3& v1, const Vector3& v2) 
    {
        return Vector3(v1.m_floats[0] + v2.m_floats[0], v1.m_floats[1] + v2.m_floats[1], v1.m_floats[2] + v2.m_floats[2]);
    }
    /**
     * @brief 向量元素乘法运算符
     * @param v1 向量1
     * @param v2 向量2
     * @return 向量元素相乘的结果
     */
    inline Vector3 
    operator*(const Vector3& v1, const Vector3& v2) 
    {
        return Vector3(v1.m_floats[0] * v2.m_floats[0], v1.m_floats[1] * v2.m_floats[1], v1.m_floats[2] * v2.m_floats[2]);
    }
    /**
     * @brief 向量减法运算符
     * @param v1 向量1
     * @param v2 向量2
     * @return 相减后的向量
     */
    inline Vector3 
    operator-(const Vector3& v1, const Vector3& v2)
    {
        return Vector3(v1.m_floats[0] - v2.m_floats[0], v1.m_floats[1] - v2.m_floats[1], v1.m_floats[2] - v2.m_floats[2]);
    }
    /**
     * @brief 向量取反运算符
     * @param v 向量
     * @return 取反后的向量
     */
    inline Vector3 
    operator-(const Vector3& v)
    {
        return Vector3(-v.m_floats[0], -v.m_floats[1], -v.m_floats[2]);
    }
    /**
     * @brief 向量与标量的乘法运算符
     * @param v 向量
     * @param s 标量
     * @return 向量与标量相乘的结果
     */
    inline Vector3 
    operator*(const Vector3& v, const double& s)
    {
        return Vector3(v.m_floats[0] * s, v.m_floats[1] * s, v.m_floats[2] * s);
    }
    /**
     * @brief 标量与向量的乘法运算符
     * @param s 标量
     * @param v 向量
     * @return 标量与向量相乘的结果
     */
    inline Vector3 
    operator*(const double& s, const Vector3& v)
    { 
        return v * s; 
    }
    /**
     * @brief 向量除以标量的运算符
     * @param v 向量
     * @param s 标量
     * @return 向量除以标量的结果
     */
    inline Vector3
    operator/(const Vector3& v, const double& s)
    {
        myAssert(s != double(0.0));
        return v * (double(1.0) / s);
    }
    /**
     * @brief 向量除以向量的运算符
     * @param v1 向量1
     * @param v2 向量2
     * @return 向量除以向量的结果
     */
    inline Vector3
    operator/(const Vector3& v1, const Vector3& v2)
    {
        return Vector3(v1.m_floats[0] / v2.m_floats[0],v1.m_floats[1] / v2.m_floats[1],v1.m_floats[2] / v2.m_floats[2]);
    }
    /**
     * @brief 计算两个向量的点积
     * @param v1 向量1
     * @param v2 向量2
     * @return 点积结果
     */
    inline double tfDot(const Vector3& v1,const Vector3& v2)
    {
        return v1.dot(v2);
    }
    /**
     * @brief 计算两个向量之间的夹角
     * @param v1 向量1
     * @param v2 向量2
     * @return 夹角结果
     */
    inline double
    tf2Angle(const Vector3& v1, const Vector3& v2) 
    { 
        return v1.angle(v2); 
    }
    /**
     * @brief 计算两个向量的叉积
     * @param v1 向量1
     * @param v2 向量2
     * @return 叉积结果
     */
    inline Vector3 
    tf2Cross(const Vector3& v1, const Vector3& v2) 
    { 
        return v1.cross(v2); 
    }
    /**
     * @brief 计算两个向量之间的距离
     * @param v1 向量1
     * @param v2 向量2
     * @return 距离结果
     */
    inline double
    tf2Distance(const Vector3& v1, const Vector3& v2) 
    { 
        return v1.distance2(v2); 
    }
    /**
     * @brief 计算该向量与另一个向量的距离
     * @param v 另一个向量
     * @return 距离结果
     */
    inline double Vector3::distance(const Vector3& v) const
    {
        return (v - *this).length();
    }
    /**
     * @brief 计算该向量与另一个向量的平方距离
     * @param v 另一个向量
     * @return 平方距离结果
     */
    inline double Vector3::distance2(const Vector3& v) const
    {
        return (v - *this).length2();
    }
}
#endif
/********************<end>********************/